#include <stdio.h>
#include <stdlib.h>

#include "Util.h"

#define NUM_SEQUENTIAL_READS 10

void doSequentialReads(char *buffer, long bufferSize, long numReads);
void doRandOffsetAndSequentialReads(char *buffer, long bufferSize,
		long numReads);
void doRandomReads(char *buffer, long bufferSize, long numReads);

int main(int argc, char *argv[]) {
	long bufferSize, numReads, i;
	char *buffer = NULL;
	struct timespec startTime, endTime;
	double timeToDoMalloc = 0, timeForRandomReads = 0;

	//printStandardMemory();
	validateAndFillInputArguments(argc, argv, &bufferSize, "BufferSize",
			&numReads, "NumReads");
	printf("Memory to allocate %s and number of reads %lu \n",
			getSizeInMB(bufferSize), numReads);

	srand(time(NULL ));
	clock_gettime(CLOCK_REALTIME, &startTime);
	buffer = (char*) malloc(sizeof(char) * bufferSize);
	if (buffer == NULL ) {
		perror("Error while allocating memory to buffer\n");
		return EXIT_FAILURE;
	} else {
		fillAllocatedMemory(buffer, bufferSize);
	}
	clock_gettime(CLOCK_REALTIME, &endTime);
	timeToDoMalloc = getDiffInNanoSeconds(startTime, endTime);
	printf("Time to alloc %lu  is \t %6.3f ns \n", bufferSize / ONE_MB,
			timeToDoMalloc);

	clock_gettime(CLOCK_REALTIME, &startTime);
	//doRandomReads(buffer, bufferSize, numReads);
	doSequentialReads(buffer, bufferSize, numReads);
	//doRandOffsetAndSequentialReads(buffer, bufferSize, numReads);
	clock_gettime(CLOCK_REALTIME, &endTime);
	timeForRandomReads = getDiffInNanoSeconds(startTime, endTime);

	printf(
			"Time for %lu randomReads is %6.3f ns. \t Time/randomRead is %6.3f\n",
			numReads, timeForRandomReads,
			timeForRandomReads / (double) numReads);

	free(buffer);

	return EXIT_SUCCESS;
}

void doSequentialReads(char *buffer, long bufferSize, long numReads) {
	long offset = 0, nextOffset = 0;
	int counter = 0, INCREMENT = 1;
	char c;
	offset = rand() % bufferSize;
	for (counter = 0; counter < numReads; counter++) {
		nextOffset = getNextOffsetWithinPage(offset, INCREMENT, bufferSize);
		swapCharacters(buffer, offset, nextOffset);
		offset = nextOffset;
	}
}

void doRandOffsetAndSequentialReads(char *buffer, long bufferSize,
		long numReads) {
	long numRandOffsets = numReads / NUM_SEQUENTIAL_READS, offset = 0,
			nextOffset = 0;
	int counter = 0, INCREMENT = 1, i = 0;
	char c;
	for (counter = 0; counter < numRandOffsets; counter++) {
		offset = rand() % bufferSize;
		for (i = 0; i < NUM_SEQUENTIAL_READS; i++) {
			nextOffset = getNextOffsetWithinPage(offset, INCREMENT, bufferSize);
			swapCharacters(buffer, offset, nextOffset);
			offset = nextOffset;
		}
	}
}

void doRandomReads(char *buffer, long bufferSize, long numReads) {
	long offset = 0, nextOffset;
	int counter = 0, randIncrement = 0;
	for (counter = 0; counter < numReads; counter++) {
		offset = rand() % bufferSize;
		randIncrement = rand() % ONE_KB;
		nextOffset = getNextOffsetWithinPage(offset, randIncrement, bufferSize);
		swapCharacters(buffer, offset, nextOffset);
	}
}
